package fauxman.utilities;

import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Collection;

import fauxman.Enums.GameElementName;
import fauxman.StaticElements.PlayableArea;
import fauxman.StaticElements.Wormhole;
import fauxman.interfaces.DynamicElement;
import fauxman.interfaces.GameElement;
import fauxman.interfaces.MoveableElement;
import fauxman.model.Hitbox;
import fauxman.model.WorldModel;

public final class ActionUtil {
	public static final int CONTINUOUS_UNITS = 3;	// 2 because our pixel per unit is twice the original pacman
	public static final int DISCRETE_UNITS = 1;
	private static int PIXELS_PER_UNIT;
	
	public static final int[] NORTH = {0,-1};
	public static final int[] EAST = {1,0};
	public static final int[] SOUTH = {0,1};
	public static final int[] WEST = {-1,0};
	public static final int[] NORTH_EAST = { 1 , -1 };
	public static final int[] NORTH_WEST = { -1, -1};
	public static final int[] SOUTH_EAST = { 1, 1};
	public static final int[] SOUTH_WEST = { -1, 1};
	
	public static Point getNextPosition(Point p, int units, int[] dir) {
		return new Point(p.x + dir[0]*units,p.y + dir[1]*units);
	}
	
	/*
		if Pacman hits
		- food -> delete food -> increase score
		- bonus -> delete bonus -> increase score
		- normal ghost -> lose life
		- vulnerable ghost -> change ghost to eaten -> increase score
		- eaten ghost -> nothing
		- pellet -> delete pellet -> increase score -> change ghost to vulnerable
	*/
	public static boolean executeAction(MoveableElement me, WorldModel model, int[] dir) {
		
		boolean confirmPlayableArea = simulateAction(me,model, dir);
		Point oldP = me.getContinuousPosition();
		Point newP = getNextPosition(oldP, CONTINUOUS_UNITS, dir);
		PIXELS_PER_UNIT = model.getPixelsPerUnit();
		
		me.setContinuousPosition(newP);
		
		if(!confirmPlayableArea){
			
//			if(me.getEnum() != GameElementName.FAUXMAN && me.getEnum() != GameElementName.BONUS)
//				System.out.println("Action: "+me.getCurrentDirection()[0]+, " "+me.getCurrentDirection()[1]);
			
			for(Wormhole wh: model.getWormholes()){
				if(Hitbox.hit(wh.getConHitbox(), me.getConHitbox())){
					me.setContinuousPosition(wh.getContinuousDestination());
					me.setDiscretePosition(new Point((int)wh.getDiscreteDestination().getX(),(int)wh.getDiscreteDestination().getY()));
					confirmPlayableArea = true;
					break;
				}
			}
		}
		
		if(me.isCollisionNecessary()){
			Collection<DynamicElement> hitDE = new ArrayList<DynamicElement>(); 
			for(DynamicElement de: model.getDynamicElements()){
				if(me != de && me.getDiscretePosition().x == de.getDiscretePosition().x && me.getDiscretePosition().y == de.getDiscretePosition().y){
					hitDE.add(de);
				}
			}
			for(DynamicElement de: hitDE){
				me.collide(model, de);
			}
		}
		
		//TODO: Add Wormholes to this, add ghost house end pixel
		int[] updatedDir = me.reactToCurrentContinuousPosition();
		if(updatedDir != null)
		{
			dir = updatedDir;
		}
		
		//Don't move if off the map
		if(confirmPlayableArea){
			//Move discretePosition if applicable
			Rectangle tile = new Rectangle(PIXELS_PER_UNIT*(int)me.getDiscretePosition().getX(), PIXELS_PER_UNIT*(int)me.getDiscretePosition().getY(), PIXELS_PER_UNIT, PIXELS_PER_UNIT);
			if(!(Hitbox.hit(tile, me.getConHitbox()))){	// if hitbox has moved completely to the next tile, then change tiles

				
				//update current Discrete position
				//TODO: this might be an issue after cornering
				me.setDiscretePosition(getNextPosition(me.getDiscretePosition(), DISCRETE_UNITS, dir));
				
				//ADD Code if we hit special tiles
				me.reactToCurrentDiscretePosition();
				
				//Update lookahead
				Point lookAhead;
				ArrayList<ArrayList<ArrayList<GameElement>>> dBoard = model.getDiscreteBoard();
				lookAhead = getNextPosition(me.getDiscretePosition(), DISCRETE_UNITS, dir);
				//Special case if the lookahead hits wormhole
				for(GameElement ge: dBoard.get((int)me.getDiscretePosition().getY()).get((int)me.getDiscretePosition().getX())){
					if(ge.getEnum() == GameElementName.WORMHOLE){
						lookAhead.setLocation(((Wormhole) ge).getDiscreteDestination());
					}
				}
				me.setLookAhead(lookAhead);
				//turn future ghost
			}
		}
		else{
			me.setContinuousPosition(oldP);
			return false;
		}
		return true;
	}
	
	public static boolean simulateAction(MoveableElement me, WorldModel model, int[] dir){
		Point oldP = me.getContinuousPosition();
		Point newP = getNextPosition(oldP, CONTINUOUS_UNITS, dir);
		boolean confirmPlayableArea = false;
		
		me.setContinuousPosition(newP);
		for(PlayableArea pa: me.getPlayableArea()){
			if(pa.getConHitbox().contains(me.getConHitbox())){
				confirmPlayableArea = true;
				break;
			}
		}
		
		//Don't move if off the map
		me.setContinuousPosition(oldP);
		return confirmPlayableArea;
	}
}
